package com.zhiwei.msf.app.service.impl;

import java.io.IOException;
import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.CreateBranchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.api.MergeResult;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.springframework.stereotype.Service;

import com.zhiwei.msf.app.constants.GitConstants;
import com.zhiwei.msf.app.dto.GitBranchInfo;
import com.zhiwei.msf.app.service.GitBranchService;

/**
 * function author zhiwei.yang time 2020-3-4-15:34
 */
@Service
public class GitBranchServiceImpl implements GitBranchService {

	@Override
	public String getCurrentBranch(Git git) throws IOException {
		return git.getRepository().getBranch();
	}

	@Override
	public GitBranchInfo getBranchList(Git git) throws GitAPIException {
		GitBranchInfo gitBranchInfo = new GitBranchInfo();
		List<Ref> branchRefList = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call();
		if (CollectionUtils.isEmpty(branchRefList)) {
			return gitBranchInfo;
		}
		branchRefList.forEach(ref -> {
			if (ref.getName().contains(GitConstants.localBranchPrefix)) {
				gitBranchInfo.getLocalBranchList().add(ref.getName());
				gitBranchInfo.getLocalBranchRefMap().put(Repository.shortenRefName(ref.getName()), ref);
			}
			if (ref.getName().contains(GitConstants.remoteBranchPrefix)) {
				gitBranchInfo.getRemoteBranchList().add(ref.getName());
				gitBranchInfo.getRemoteBranchRefMap().put(Repository.shortenRefName(ref.getName()), ref);
			}
		});
		return gitBranchInfo;
	}

	@Override
	public boolean pullBranch(Git git, String branch) throws GitAPIException, IOException {
		if (checkoutBranch(git, branch)) {
			git.pull().call();
			return true;
		}
		return false;
	}

	@Override
	public boolean checkoutBranch(Git git, String branch) throws GitAPIException, IOException {
		return this.checkoutBranch(git, branch, false);
	}

	@Override
	public boolean checkoutBranch(Git git, String branch, boolean force) throws GitAPIException, IOException {

		// 当前工作分支相同，无需切换
		if (getCurrentBranch(git).equals(branch)) {
			return true;
		}

		GitBranchInfo gitBranchInfo = getBranchList(git);
		// 存在分支本地
		if (gitBranchInfo.isExistLocalBranch(branch)) {
			git.checkout().setCreateBranch(false).setName(branch).call();
			return true;
		}

		// 本地分支不存在，无需强制创建，返回false
		if (!force) {
			return false;
		}

		// 不存在本地分支, 远程分支存在则创建，否则本地创建
		if (gitBranchInfo.isExistRemoteBranch(branch)) {
			git.checkout().setCreateBranch(true).setName(branch)
					.setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK)
					.setStartPoint(GitConstants.remoteBranchNamePrefix.concat(branch)).call();
			return true;
		}
		git.checkout().setCreateBranch(true).setName(branch).call();
		return true;
	}

	@Override
	public boolean mergeBranch(Git git, String targetBranch, String sourceBranch) throws GitAPIException, IOException {
		if (StringUtils.isEmpty(targetBranch) || StringUtils.isEmpty(sourceBranch)) {
			return false;
		}
		GitBranchInfo gitBranchInfo = getBranchList(git);
		if (!gitBranchInfo.isExistLocalBranch(targetBranch) || !gitBranchInfo.isExistLocalBranch(sourceBranch)) {
			return false;
		}
		if (!getCurrentBranch(git).equals(targetBranch)) {
			this.checkoutBranch(git, targetBranch);
		}
		Ref sourceBranchRef = gitBranchInfo.getLocalBranchRef(sourceBranch);
		MergeResult mergeResult = git.merge().include(sourceBranchRef).call();
		return CollectionUtils.isEmpty(mergeResult.getCheckoutConflicts());
	}
}
